<template>
    <div id="map"></div>
</template>

<script>
import * as dat from 'dat.gui';
import * as maptalks from 'maptalks';
import { ThreeLayer } from 'maptalks.three';
import * as Stats from 'stats.js';
import * as THREE from 'three';

// 可选的draco插件
// import '@maptalks/transcoders.draco';
// 可选的crn纹理解析插件
// import '@maptalks/transcoders.crn';
// 可选的ktx2纹理解析插件
// import '@maptalks/transcoders.ktx2';
import { Geo3DTilesLayer } from '@maptalks/3dtiles';
import { GroupGLLayer } from '@maptalks/gl';

import { LineTrip } from '../class/effects/LineTrip';
import { RippleWall } from '../class/effects/RippleWall';
import { SpriteLine } from '../class/effects/SpriteLine';
import { GeoUtil } from '../class/geoutil/index';
import * as meshline from '../class/meshline/main';

export default {
  name: "three",
  data() {
    return {
      // stats: null,
      meshes: [],
      buidingColor: "#0fdaf5",
      OPTIONS: {
        speed: 0,
        time: 0,
      },
    };
  },
  mounted() {
    this.$nextTick(() => {
      this.mapinit();
    });
  },
  methods: {
    // 初始化地图
    mapinit() {
      let map = new maptalks.Map("map", {
        center: [108.93214209100012, 34.243681617400284],
        zoom: 16.118,
        pitch: 60,
        centerCross: true,
        doubleClickZoom: false,
        baseLayer: new maptalks.TileLayer("tile", {
          // urlTemplate: "http://mt0.google.cn/vt/lyrs=m&x={x}&y={y}&z={z}",
          cssFilter: "sepia(100%) invert(95%)",
          urlTemplate: "http://map.geoq.cn/arcgis/rest/services/ChinaOnlineStreetPurplishBlue/MapServer/tile/{z}/{y}/{x}",   //geoq
          // urlTemplate:
          //   "http://wprd0{s}.is.autonavi.com/appmaptile?x={x}&y={y}&z={z}&lang=zh_cn&size=1&scl=2&style=7", //gaode
          subdomains: [1, 2, 3, 4],
        }),
      });
      window.map = map;
      this.addToolbar();
      var threeLayer = new ThreeLayer("threelayer", {
        identifyCountOnEvent: 1,
        forceRenderOnMoving: true,
      });
      let stats;
      window.threeLayer = threeLayer;
      window.vueinstance = this;
      threeLayer.prepareToDraw = function (gl, scene, camera) {
        console.log(this);
        stats = new Stats();
        window.vueinstance.stats = stats;
        stats.domElement.style.zIndex = 100;
        document.getElementById("map").appendChild(stats.domElement);
        scene.add(new THREE.AmbientLight(0xffffff, 0.6));
        camera.add(new THREE.SpotLight(0xffffff, 0.6, 0, Math.PI));
        window.vueinstance.loadBuilding();
        window.vueinstance.animation();
      };
      threeLayer.addTo(map);
    },

    // ui按钮
    addToolbar() {
      var that = this;
      new maptalks.control.Toolbar({
        items: [
          {
            item: "二维建筑",
            click: function () {
              window.map.removeLayer(window.groupLayer);
              that.loadBuilding();
            },
          },
          {
            item: "实景三维",
            click: function () {
              window.threeLayer.removeMesh(window.meshes);
              window.threeLayer._baseObjects = [];
              window.meshes.forEach((mesh) => {
                mesh.getObject3d().geometry.dispose();
                for (const key in mesh) {
                  mesh[key] = null;
                }
                mesh = null;
              });
              window.meshes.length = 0;
              that.load3dTileset();
            },
          },
          {
            item: "动态围栏",
            click: function () {
              that.addWall();
            },
          }
        ],
      }).addTo(window.map);
    },
    animation() {
      // layer animation support Skipping frames
      window.threeLayer._needsUpdate = !window.threeLayer._needsUpdate;
      if (window.threeLayer._needsUpdate) {
        window.threeLayer.redraw();
      }
      this.stats.update();
      requestAnimationFrame(this.animation);
    },

    // 二维建筑
    loadBuilding() {
      let url = "data/xian_beilin_0320.geojson";
      let that = this;
      fetch(url)
        .then(function (res) {
          return res.text();
        })
        .then(function (text) {
          return JSON.parse(text).features;
        })
        .then(function (features) {
          let extrudeFactor = 1;
          let meshes = [];
          for (let feature of features) {
            let height = feature.properties.height || 1;
            let material = new THREE.MeshPhongMaterial({
              color: that.getColor(height),
            });
            let extrudePolygon = window.threeLayer.toExtrudePolygon(
              maptalks.GeoJSON.toGeometry(feature),
              {
                interactive: false,
                height: extrudeFactor * height,
                topColor: that.buidingColor,
              },
              material
            );
            window.threeLayer.addMesh(extrudePolygon);
            meshes.push(extrudePolygon);
          }
          window.meshes = meshes;
        });
    },
    // 三维建筑
    load3dTileset() {
      const layer = new Geo3DTilesLayer("3dtiles", {
        // offset: function (center) {
        //     const res = map.getGLRes();
        //     // 坐标由 WGS84 转为 GCJ02
        //     const c = maptalks.CRSTransform.transform(center.toArray(), 'WGS84', 'GCJ02');
        //     const coord = map.coordToPointAtRes(new maptalks.Coordinate(c), res);
        //     const offset = map.coordToPointAtRes(center, res)._sub(coord);
        //     return offset._round().toArray();
        // },
        maxGPUMemory: 512, //最大缓存数，单位 M bytes
        // loadingLimitOnInteracting : 1, //地图交互过程中瓦片请求最大数量
        // loadingLimit : 0, //瓦片请求最大数量
        services: [
          {
            //data from cesiumlab
            url: "https://earthsdk.com/v/last/Apps/assets/dayanta/tileset.json",
            // maximumScreenSpaceError值越小，加载的模型越清晰，但加载的数据量会变大
            // 清晰度可以接受的情况下，推荐把这个值设得越大越好，性能会越好
            maximumScreenSpaceError: 12.0,
            // 数据请求的额外参数
            // urlParams: 'v=0.0',
            // ajax请求的额外参数
            // ajaxOptions : { credentials : 'include' },
            // 把模型降低指定高度，单位米
            heightOffset: -400,
            // 环境光照值，倾斜摄影可以设为[1.0, 1.0, 1.0]获得最清晰的效果，非倾斜摄影可以适当降低，例如设为 [0.2, 0.2, 0.2]
            // 如果不设置，则采用地图上的默认光照值
            ambientLight: [1.0, 1.0, 1.0],
            // maxExtent: maxExtent
          },
          // 其他的3dtiles数据源
        ],
      });
      // 添加到GroupGLLayer中
      // GroupGLLayer能实现抗锯齿等后处理，也能加入其他三维图层，让子图层都融合到同一个三维空间中
      const sceneConfig = {
        postProcess: {
          enable: true,
          antialias: {
            enable: true,
          },
        },
      };
      const groupLayer = new GroupGLLayer("group", [layer], {
        sceneConfig,
      });
      groupLayer.addTo(window.map);

      window.groupLayer = groupLayer;
      // layer.once("loadtileset", (e) => {
      //   const extent = layer.getExtent(e.index);
      //   window.map.fitExtent(extent, 0, { animation: false });
      // });
    },

    // 模型设置颜色
    getColor(height) {
      let rgb;
      if (height < 20) {
        rgb = '100,100,100';
      }
      else if (height >= 20 && height < 80) {
        rgb = '200,200,200';
      }
      else if (height >= 80 && height < 160) {
        rgb = '300,300,300';
      }
      else if (height >= 160 && height < 300) {
        rgb = '500,500,500';
      }
      else {
        rgb = '1,0,0';
      }
      return `rgb(${rgb})`;
    },

    // 动态围栏
    addWall() {
      const vertexs = {
        normal_vertex: "\n  precision lowp float;\n  precision lowp int;\n  "
          .concat(
            THREE.ShaderChunk.fog_pars_vertex,
            "\n  varying vec2 vUv;\n  void main() {\n    vec4 mvPosition = modelViewMatrix * vec4( position, 1.0 );\n    vUv = uv;\n    gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);\n    "
          )
          .concat(THREE.ShaderChunk.fog_vertex, "\n  }\n"),
      };

      const fragments = {
        rippleWall_fragment:
          "\n  precision lowp float;\n  precision lowp int;\n  uniform float time;\n  uniform float opacity;\n  uniform vec3 color;\n  uniform float num;\n  uniform float hiz;\n\n  varying vec2 vUv;\n\n  void main() {\n    vec4 fragColor = vec4(0.);\n    float sin = sin((vUv.y - time * hiz) * 10. * num);\n    float high = 0.92;\n    float medium = 0.4;\n    if (sin > high) {\n      fragColor = vec4(mix(vec3(.8, 1., 1.), color, (1. - sin) / (1. - high)), 1.);\n    } else if(sin > medium) {\n      fragColor = vec4(color, mix(1., 0., 1.-(sin - medium) / (high - medium)));\n    } else {\n      fragColor = vec4(color, 0.);\n    }\n\n    vec3 fade = mix(color, vec3(0., 0., 0.), vUv.y);\n    fragColor = mix(fragColor, vec4(fade, 1.), 0.85);\n    gl_FragColor = vec4(fragColor.rgb, fragColor.a * opacity * (1. - vUv.y));\n  }\n",
      };
      const material = new THREE.ShaderMaterial({
        uniforms: {
          time: {
            type: "pv2",
            value: 0,
          },
          color: {
            type: "uvs",
            value: new THREE.Color("#00A2E8"),
          },
          opacity: {
            type: "pv2",
            value: 0.5,
          },
          num: {
            type: "pv2",
            value: 10,
          },
          hiz: {
            type: "pv2",
            value: 0.15,
          },
        },
        vertexShader: vertexs.normal_vertex,
        fragmentShader: fragments.rippleWall_fragment,
        blending: THREE.AdditiveBlending,
        transparent: !0,
        depthWrite: !1,
        depthTest: !0,
        side: THREE.DoubleSide,
      });
      let rippleWall = new RippleWall(
        [
          [108.99815531300004, 34.2446689070001],
          [108.99245241900007, 34.244664513000004],
          [108.9603704190001, 34.231515744],
          [108.9257934190001, 34.23150174500008],
          [108.90492841900007, 34.24073958200006],
          [108.90543141900012, 34.24150556900002],
          [108.90544541900003, 34.24675247700001],
          [108.90651042000005, 34.24822345100004],
          [108.90883442000005, 34.248258451000005],
          [108.9088414190001, 34.24894743800008],
          [108.90896842000004, 34.24896143800008],
          [108.90901341900012, 34.24955642700011],
          [108.91556441900009, 34.2495284280001],
          [108.91555142000009, 34.25018841700008],
          [108.9187204190001, 34.25017941600005],
          [108.91871742000002, 34.252199381000025],
          [108.93132846200004, 34.252328394000045],
          [108.93123114200006, 34.260962982000024],
          [108.94259857600012, 34.26064228200004],
          [108.94307242000006, 34.26135922000003],
          [108.94343741900006, 34.26148321799999],
          [108.96778542000007, 34.26143921900008],
          [108.96746842000003, 34.26905208500008],
          [108.9981375690001, 34.26907216400005],
          [108.99815531300004, 34.2446689070001]
        ],
        { height: 200 },
        material,
        window.threeLayer
      );
      window.threeLayer.addMesh(rippleWall);
    },
  },
};
</script>

<style scoped>
#map {
  width: 100%;
  height: 100%;
  padding: 0;
  margin: 0;
}
</style>
